require('dotenv').config();
const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
const multer = require('multer');
const path = require('path');
const WebSocket = require('ws');//使用TCP的websocket
//const password ='WUPEIhao0926'
const app = express();
const PORT = process.env.PORT || 3000;
const MONGO_URI = process.env.MONGO_URI || 'mongodb://localhost:27017/userdb';
// 云端数据库 URI
const CLOUD_URI =
    'mongodb+srv://1186036686:WUPEIhao0926@cluster0.29z94.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0';
// 本地数据库 URI
const LOCAL_URI = 'mongodb://localhost:27017/userdb';
const password = process.env.DB_PASSWORD; // 获取密码

mongoose.connect(CLOUD_URI)
    .then(() => console.log('MongoDB 连接成功'))
    .catch(err => console.error('MongoDB 连接失败:', err));
// 定义用户数据模型
const UserSchema = new mongoose.Schema({
    userid: String,
    password: String
});
const LostItemSchema = new mongoose.Schema({
    name: { type: String, required: true },
    type: { type: String, required: true },
    latitude: { type: Number, required: true },
    longitude: { type: Number, required: true },
    description: { type: String },
    imageUrl: { type: String, default: '' },
    uniqueId: { type: String, required: true },
    status: { type: String, required: true }
});
const User = mongoose.model('User', UserSchema);
// 添加 HTTP 服务器支持 WebSocket
const server = require('http').createServer(app);
const wss = new WebSocket.Server({ server });

wss.on('connection', function connection(ws) {
    console.log('客户端已连接');

    ws.on('message', function incoming(message) {
        console.log('收到消息:', message.toString());
        // 回复客户端
        ws.send(JSON.stringify({
            status: 200,
            message: "收到消息：" + message.toString()
        }));
    });

    ws.on('close', () => {
        console.log('客户端已断开连接');
    });
});

// // 启动 HTTP + WebSocket 服务
// server.listen(PORT, () => {
//     console.log(`服务器已启动，监听端口 ${PORT}`);
// });
//

app.use(express.json()); // 解析 JSON 请求体

// const LostItemSchema = new mongoose.Schema({
//     name: {
//         type: String,
//         required: true,
//     },
//     type: {
//         type: String,
//         required: true,
//     },
//     location: {
//         latitude: {
//             type: Number,
//             required: true,
//         },
//         longitude: {
//             type: Number,
//             required: true,
//         },
//     },
//     description: {
//         type: String,
//     },
//     imageUrl: {
//         type: String,
//         default: '',
//     },
//     uniqueId: {
//         type: String,
//         required: true,
//     }
// });


// 添加 2dsphere 索引
LostItemSchema.index({ location: '2dsphere' });

const LostItem = mongoose.model('LostItem', LostItemSchema);
// 查询附近500m内的“捡到失物”
app.get('/found-items-in-range', async (req, res) => {
    const { latitude, longitude } = req.query;

    if (!latitude || !longitude) {
        return res.status(400).json({ success: false, message: '缺少必填参数: latitude, longitude' });
    }

    try {
        const foundItems = await LostItem.aggregate([
            {
                $geoNear: {
                    near: { type: "Point", coordinates: [parseFloat(longitude), parseFloat(latitude)] },
                    distanceField: "dist.calculated",
                    maxDistance: 500,
                    spherical: true,
                }
            },
            {
                $match: { status: '捡到失物' }
            }
        ]);

        res.json({ success: true, message: '查询成功', data: foundItems });
    } catch (error) {
        console.error('查询失败:', error);
        res.status(500).json({ success: false, message: '查询失败', error: error.message });
    }
});

app.get('/matched-lost-items', async (req, res) => {
    const { userId, latitude, longitude, maxDistance } = req.query;

    if (!userId || !latitude || !longitude) {
        return res.status(400).json(ApiResponse.error('缺少必填参数: userId, latitude, longitude'));
    }
    try {
        // 1. 先查询当前用户发布的“寻找失物”信息
        const userLostItems = await LostItem.find({ userId, status: '寻找失物' });

        if (!userLostItems.length) {
            return res.json(ApiResponse.success('当前用户没有发布寻找失物信息', []));
        }
        // 2. 构建匹配条件（模糊匹配 name 和 type）
        const matchConditions = userLostItems.map(item => ({
            $or: [
                { name: { $regex: item.name, $options: 'i' } }, // 物品名称相似匹配
                { type: { $regex: item.type, $options: 'i' } }  // 物品类别相似匹配
            ]
        }));
        // 3. 使用 $geoNear + $match 进行查询
        const matchedItems = await LostItem.aggregate([
            {
                $geoNear: {
                    near: { type: "Point", coordinates: [parseFloat(longitude), parseFloat(latitude)] },
                    distanceField: "dist.calculated",
                    maxDistance: parseFloat(maxDistance) || 500, // 默认500m
                    spherical: true,
                }
            },
            {
                $match: {
                    status: '捡到失物',
                    $or: matchConditions
                }
            }
        ]);

        res.json(ApiResponse.success('匹配成功', matchedItems));
    } catch (error) {
        console.error('查询失败:', error);
        res.status(500).json(ApiResponse.error('查询失败', error.message));
    }
});

app.get('/quick-match', async (req, res) => {
    const { userId, latitude, longitude } = req.query;

    if (!userId || !latitude || !longitude) {
        return res.status(400).json(ApiResponse.error('缺少参数'));
    }

    try {
        // 1️⃣ 查询当前用户的 “寻找失物”
        const userLostItems = await LostItem.find({ userId, status: '寻找失物' });

        if (!userLostItems.length) {
            return res.json(ApiResponse.success('未找到你的失物信息', []));
        }

        // 2️⃣ 查询附近 500m 内的 “捡到失物”
        const foundItems = await LostItem.aggregate([
            {
                $geoNear: {
                    near: { type: "Point", coordinates: [parseFloat(longitude), parseFloat(latitude)] },
                    distanceField: "dist.calculated",
                    maxDistance: 500,
                    spherical: true,
                }
            },
            { $match: { status: '捡到失物' } }
        ]);

        // 3️⃣ 计算匹配度
        const results = [];
        for (const lostItem of userLostItems) {
            for (const foundItem of foundItems) {
                const score = computeSimilarity(lostItem.name, foundItem.name) +
                computeSimilarity(lostItem.type, foundItem.type);

                if (score > 0.5) { // 设定匹配度阈值
                    results.push({ lostItem, foundItem, matchScore: score });
                }
            }
        }

        // 4️⃣ 按匹配度排序
        results.sort((a, b) => b.matchScore - a.matchScore);

        // 5️⃣ 触发 WebSocket 通知
        if (results.length) {
            io.emit(`match-found-${userId}`, { message: '找到匹配物品', data: results });
        }

        res.json(ApiResponse.success('匹配成功', results));
    } catch (error) {
        console.error('查询失败:', error);
        res.status(500).json(ApiResponse.error('查询失败', error.message));
    }
});

// 配置 multer 存储设置
const storage = multer.diskStorage({
    destination: (req, file, cb) => {
        // 设置上传文件存储的路径
        cb(null, 'uploads/');
    },
    filename: (req, file, cb) => {
        // 设置文件名
        cb(null, Date.now() + path.extname(file.originalname)); // 保持文件扩展名
    }
});

const upload = multer({
    storage: storage,
    limits: { fileSize: 5 * 1024 * 1024 }, // 限制文件大小为 5MB
    fileFilter: (req, file, cb) => {
        const allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
        if (!allowedTypes.includes(file.mimetype)) {
            return cb(null, false, new Error('不支持的文件类型'));
        }
        cb(null, true);
    }
});

// 上传图片接口
app.post('/upload-image', upload.single('img'), async (req, res) => {
    if (!req.file) {
        return res.status(400).json({
            code: 1,
            message: '未上传文件',
            err: 'File is missing'
        });
    }

    // 检查是否有其他必需的字段
    const { description, type, location, uniqueId } = req.body;
    if (!description || !type || !location || !uniqueId) {
        return res.status(400).json({
            code: 5,
            message: '缺少必填参数',
            err: 'Missing required fields'
        });
    }
    // 文件类型验证错误
    if (req.fileValidationError) {
        return res.status(400).json({
            code: 2,
            message: '不支持的文件类型',
            err: 'Unsupported file type'
        });
    }
    // 文件大小超过限制
    if (req.file && req.file.size > 5 * 1024 * 1024) {
        return res.status(400).json({
            code: 3,
            message: '文件大小超过限制',
            err: 'File size exceeds the limit'
        });
    }

    // 生成文件的在线访问 URL
    const imageUrl = `http://localhost:${PORT}/uploads/${req.file.filename}`;

    // 创建新的失物记录并保存到数据库
    try {
        const lostItem = new LostItem({
            name: req.body.name,
            type,
            description,
            location: JSON.parse(location),
            imageUrl,
            uniqueId,
        });

        const savedItem = await lostItem.save();

        // 返回成功响应
        res.json({
            code: 0,
            message: '上传成功',
            data: {
                url: imageUrl,
                description,
                type,
                location,
                uniqueId,
                itemId: savedItem._id, // 返回数据库中保存的 itemId
            }
        });
    } catch (err) {
        console.error('数据库操作失败:', err);
        res.status(500).json({
            code: 6,
            message: '数据库操作失败',
            err: 'Database operation failed',
        });
    }
});

// 错误处理中间件
app.use((err, req, res, next) => {
    console.error(err.stack);
    res.status(500).json({
        code: 500,
        message: '服务器内部错误，请稍后再试',
        err: 'Internal server error'
    });
});

// 登录接口
app.post('/find', async (req, res) => {
    const { userid, password } = req.body;
    try {
        const user = await User.findOne({ userid });
        if (!user) {
            const response = { success: false, message: '用户不存在', code: 404 };
            console.log('Response:', response); // 打印响应内容
            return res.status(404).json(response);
        }
        if (user.password === password) {
            const response = {
                success: true,
                message: '登录成功',
                code: 200,
                data: userid
            };
            console.log('Response:', response); // 打印响应内容
            return res.json(response);
        } else {
            const response = { success: false, message: '密码错误', code: 400 };
            console.log('Response:', response); // 打印响应内容
            return res.json(response);
        }
    } catch (error) {
        console.error('查询错误:', error);
        const response = { success: false, message: '服务器错误', code: 500 };
        console.log('Response:', response); // 打印响应内容
        return res.status(500).json(response);
    }
});
app.post('/publish', async (req, res) => {
    const { userid, password } = req.body;
    // 1. 检查用户名和密码是否为空
    if (!userid || !password) {
        return res.status(400).json({
            success: false,
            code: 4001, // 使用 400 系列错误码表示客户端错误
            message: '账号和密码不能为空'
        });
    }
    // 2. 检查用户名是否包含特殊字符
    const usernamePattern = /^[a-zA-Z0-9_]+$/; // 只允许字母、数字和下划线
    if (!usernamePattern.test(userid)) {
        return res.status(400).json({
            success: false,
            code: 4002, // 错误码：400 系列表示客户端错误
            message: '账号不能包含特殊字符'
        });
    }
    // 3. 检查密码是否符合要求（包含大小写字母和数字）
    const passwordPattern = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$/; // 至少包含一个小写字母、一个大写字母和一个数字
    if (!passwordPattern.test(password)) {
        return res.status(400).json({
            success: false,
            code: 4003, // 错误码：400 系列表示客户端错误
            message: '密码应包含大小写字母和数字'
        });
    }

    try {
        // 4. 检查账号是否已存在
        const existingUser = await User.findOne({ userid });
        if (existingUser) {
            return res.status(400).json({
                success: false,
                code: 4004, // 错误码：400 系列表示客户端错误
                message: '账号已存在'
            });
        }

        // 5. 创建新用户并存入数据库
        const newUser = new User({ userid, password });
        await newUser.save();

        // 6. 返回成功信息
        res.status(200).json({
            success: true,
            code: 200, // HTTP 200 状态码表示成功
            message: '注册成功'
        });

    } catch (error) {
        console.error('注册错误:', error);
        res.status(500).json({
            success: false,
            code: 5000, // 错误码：500 系列表示服务器错误
            message: '服务器错误'
        });
    }
});




// 发布失物信息接口
app.post('/lost-items', async (req, res) => {
    try {
        const { name, type, latitude, longitude, description, uniqueId, status } = req.body;

        if (!name || !type || !latitude || !longitude || !uniqueId) {
            return res.status(400).json({
                success: false,
                message: '缺少必填字段: name, type, latitude, longitude, uniqueId'
            });
        }

        const newLostItem = new LostItem({
            name,
            type,
            latitude: parseFloat(latitude),
            longitude: parseFloat(longitude),
            description: description || '',
            uniqueId,
            status: status || '未认领'
        });

        const savedLostItem = await newLostItem.save();

        res.status(201).json({
            success: true,
            message: '失物信息发布成功',
            data: savedLostItem,
            code:200
        });
    } catch (error) {
        console.error('发布失物失败:', error);
        res.status(500).json({
            success: false,
            message: '服务器错误，无法发布失物信息',
            error: error.message
        });
    }
});


// 查询失物的距离范围接口
app.get('/lost-items-in-range', async (req, res) => {
    const { latitude, longitude, distance } = req.query;
    // 检查是否传入经纬度和距离
    if (!latitude || !longitude || !distance) {
        return res.status(400).json({ success: false, message: '缺少必填参数: latitude, longitude, distance' });
    }
    try {
        const lostItems = await LostItem.aggregate([
            {
                $geoNear: {
                    near: { type: "Point", coordinates: [parseFloat(longitude), parseFloat(latitude)] },
                    distanceField: "dist.calculated", // 计算距离并保存在dist.calculated字段
                    maxDistance: parseInt(distance), // 距离范围，单位为米
                    spherical: true, // 启用球面查询
                }
            }
        ]);
        res.json({ success: true, message: '查询成功', data: lostItems });
    } catch (error) {
        console.error('查询失物失败:', error);
        res.status(500).json({ success: false, message: '查询失败', error: error.message });
    }
});

// 查询失物的距离范围和描述接口
app.get('/lost-items-in-range-with-description', async (req, res) => {
    const { latitude, longitude, distance, description } = req.query;

    // 检查是否传入经纬度、距离和描述
    if (!latitude || !longitude || !distance || !description) {
        return res.status(400)
            .json({ success: false, message: '缺少必填参数: latitude, longitude, distance, description' });
    }
    try {
        const lostItems = await LostItem.aggregate([
            {
                $geoNear: {
                    near: { type: "Point", coordinates: [parseFloat(longitude), parseFloat(latitude)] },
                    distanceField: "dist.calculated", // 计算距离并保存在dist.calculated字段
                    maxDistance: parseInt(distance), // 距离范围，单位为米
                    spherical: true, // 启用球面查询
                }
            },
            {
                $match: {
                    description: { $regex: description, $options: 'i' } // 使用正则表达式匹配描述（忽略大小写）
                }
            }
        ]);

        res.json({ success: true, message: '查询成功', data: lostItems });
    } catch (error) {
        console.error('查询失物失败:', error);
        res.status(500).json({ success: false, message: '查询失败', error: error.message });
    }
});
    // 查询所有失物信息（不限制位置和描述）
    app.get('/all-lost-items', async (req, res) => {
        try {
            const allLostItems = await LostItem.find(); // 查询所有记录
            res.json({ success: true, message: '查询成功', data: allLostItems,status:200,code:200 });
        } catch (error) {
            console.error('查询所有失物失败:', error);
            res.status(500).json({ success: false, message: '查询失败', error: error.message });
        }
    });

//更新密码
app.post('/upd', async (req, res) => {
    const { userid, newpassword } = req.body;

    if (!userid || !newpassword) {
        return res.status(400).json({
            success: false,
            message: '用户名或新密码不能为空',
            code: 400,
        });
    }

    try {
        const user = await User.findOne({ userid });

        if (!user) {
            return res.status(404).json({
                success: false,
                message: '用户未找到',
                code: 404,
            });
        }

        user.password = newpassword;
        await user.save(); // 这里保存更改

        return res.status(200).json({
            success: true,
            message: '密码修改成功',
            code: 200
        });
    } catch (error) {
        console.error('修改密码失败:', error);
        return res.status(500).json({
            success: false,
            message: '服务器内部错误',
            code: 500,
        });
    }
});

// 服务器启动
app.listen(PORT, () => {
    console.log(`服务器运行在 http://localhost:${PORT}`);
});

